using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;

namespace App4
{
    public class FileTransferManager
    {
        private const int BufferSize = 8192;
        private const int MaxThreads = 4;

        public class DownloadProgress
        {
            public long BytesTransferred { get; set; }
            public long TotalBytes { get; set; }
            public int Percentage => TotalBytes > 0 ? (int)((BytesTransferred * 100) / TotalBytes) : 0;
            public double Speed { get; set; }
            public string EstimatedTimeRemaining => Speed > 0 ? 
                TimeSpan.FromSeconds((TotalBytes - BytesTransferred) / Speed).ToString("mm:ss") : "--:--";
        }

        // 支持进度回调的下载方法
        public static async Task DownloadFile(string sourceIp, string filePath, string savePath, Action<int> progressCallback = null)
        {
            try
            {
                // 连接到源设备
                using (var client = new TcpClient())
                {
                    await client.ConnectAsync(sourceIp, 8889);

                    // 发送下载请求
                    using (var stream = client.GetStream())
                    {
                        // 发送文件路径
                        byte[] pathBytes = System.Text.Encoding.UTF8.GetBytes(filePath);
                        byte[] lengthBytes = BitConverter.GetBytes(pathBytes.Length);
                        await stream.WriteAsync(lengthBytes, 0, lengthBytes.Length);
                        await stream.WriteAsync(pathBytes, 0, pathBytes.Length);

                        // 接收文件信息
                        byte[] fileInfoBytes = new byte[16];
                        int bytesRead = await stream.ReadAsync(fileInfoBytes.AsMemory(0, fileInfoBytes.Length));
                        if (bytesRead < fileInfoBytes.Length)
                        {
                            throw new Exception("无法读取完整的文件信息");
                        }

                        long fileSize = BitConverter.ToInt64(fileInfoBytes, 0);
                        int fileNameLength = BitConverter.ToInt32(fileInfoBytes, 8);

                        // 接收文件名
                        byte[] fileNameBytes = new byte[fileNameLength];
                        bytesRead = await stream.ReadAsync(fileNameBytes.AsMemory(0, fileNameBytes.Length));
                        if (bytesRead < fileNameBytes.Length)
                        {
                            throw new Exception("无法读取完整的文件名");
                        }

                        string fileName = System.Text.Encoding.UTF8.GetString(fileNameBytes);

                        // 创建保存目录
                        string fullSavePath = Path.Combine(savePath, fileName);

                        // 使用多线程下载并支持进度回调
                        await MultiThreadedDownload(stream, fullSavePath, fileSize, progressCallback);
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"下载文件时出错: {ex.Message}");
                throw;
            }
        }

        private static async Task MultiThreadedDownload(NetworkStream stream, string savePath, long fileSize, Action<int> progressCallback = null)
        {
            // 计算每个线程下载的块大小
            long chunkSize = fileSize / MaxThreads;
            long[] bytesDownloaded = new long[MaxThreads];
            long totalDownloaded = 0;

            // 创建文件
            using (var fileStream = new FileStream(savePath, FileMode.Create, FileAccess.Write))
            {
                fileStream.SetLength(fileSize);

                // 创建线程列表
                var tasks = new List<Task>();

                // 启动多个线程下载
                for (int i = 0; i < MaxThreads; i++)
                {
                    long startPosition = i * chunkSize;
                    long endPosition = (i == MaxThreads - 1) ? fileSize : (i + 1) * chunkSize - 1;
                    int threadIndex = i;

                    tasks.Add(DownloadChunk(stream, fileStream, startPosition, endPosition, 
                        (downloaded) => 
                        {
                            bytesDownloaded[threadIndex] = downloaded;
                            totalDownloaded = bytesDownloaded.Sum();
                            
                            if (progressCallback != null && fileSize > 0)
                            {
                                int progress = (int)((totalDownloaded * 100) / fileSize);
                                progressCallback(Math.Min(progress, 100));
                            }
                        }));
                }

                // 等待所有线程完成
                await Task.WhenAll(tasks);
                
                // 确保进度显示为100%
                if (progressCallback != null)
                {
                    progressCallback(100);
                }
            }
        }

        private static async Task DownloadChunk(NetworkStream stream, FileStream fileStream, long startPosition, long endPosition, Action<long> progressCallback = null)
        {
            try
            {
                // 通知服务器我们要下载的块
                byte[] chunkInfo = new byte[16];
                BitConverter.GetBytes(startPosition).CopyTo(chunkInfo, 0);
                BitConverter.GetBytes(endPosition).CopyTo(chunkInfo, 8);
                await stream.WriteAsync(chunkInfo, 0, chunkInfo.Length);

                // 下载数据
                byte[] buffer = new byte[BufferSize];
                long bytesRemaining = endPosition - startPosition + 1;
                long position = startPosition;
                long totalDownloaded = 0;

                while (bytesRemaining > 0)
                {
                    int bytesToRead = (int)Math.Min(BufferSize, bytesRemaining);
                    int bytesRead = await stream.ReadAsync(buffer.AsMemory(0, bytesToRead));

                    if (bytesRead == 0)
                    {
                        break; // 连接关闭
                    }

                    // 写入文件的正确位置
                    lock (fileStream)
                    {
                        fileStream.Position = position;
                        fileStream.Write(buffer, 0, bytesRead);
                    }

                    position += bytesRead;
                    totalDownloaded += bytesRead;
                    bytesRemaining -= bytesRead;
                    
                    // 更新进度
                    progressCallback?.Invoke(totalDownloaded);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"下载块时出错: {ex.Message}");
                throw;
            }
        }
        // 支持多线程和详细进度报告的下载方法
        public static async Task DownloadFileWithThreads(string sourceIp, string filePath, string savePath, int threadCount, IProgress<DownloadProgress> progress = null)
        {
            try
            {
                // 连接到源设备
                using (var client = new TcpClient())
                {
                    await client.ConnectAsync(sourceIp, 8889);

                    // 发送下载请求
                    using (var stream = client.GetStream())
                    {
                        // 发送文件路径
                        byte[] pathBytes = System.Text.Encoding.UTF8.GetBytes(filePath);
                        byte[] lengthBytes = BitConverter.GetBytes(pathBytes.Length);
                        await stream.WriteAsync(lengthBytes, 0, lengthBytes.Length);
                        await stream.WriteAsync(pathBytes, 0, pathBytes.Length);

                        // 接收文件信息
                        byte[] fileInfoBytes = new byte[16];
                        int bytesRead = await stream.ReadAsync(fileInfoBytes.AsMemory(0, fileInfoBytes.Length));
                        if (bytesRead < fileInfoBytes.Length)
                        {
                            throw new Exception("无法读取完整的文件信息");
                        }

                        long fileSize = BitConverter.ToInt64(fileInfoBytes, 0);
                        int fileNameLength = BitConverter.ToInt32(fileInfoBytes, 8);

                        // 接收文件名
                        byte[] fileNameBytes = new byte[fileNameLength];
                        bytesRead = await stream.ReadAsync(fileNameBytes.AsMemory(0, fileNameBytes.Length));
                        if (bytesRead < fileNameBytes.Length)
                        {
                            throw new Exception("无法读取完整的文件名");
                        }

                        string fileName = System.Text.Encoding.UTF8.GetString(fileNameBytes);

                        // 创建保存目录
                        string fullSavePath = Path.Combine(savePath, fileName);

                        // 使用多线程下载
                        await MultiThreadedDownloadWithProgress(sourceIp, filePath, fullSavePath, fileSize, threadCount, progress);
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"下载文件时出错: {ex.Message}");
                throw;
            }
        }

        private static async Task MultiThreadedDownloadWithProgress(string sourceIp, string filePath, string savePath, long fileSize, int threadCount, IProgress<DownloadProgress> progress)
        {
            if (threadCount <= 0) threadCount = 1;
            if (threadCount > 10) threadCount = 10;

            long chunkSize = fileSize / threadCount;
            long[] bytesDownloaded = new long[threadCount];
            DateTime startTime = DateTime.Now;
            object lockObject = new object();

            // 创建文件
            using (var fileStream = new FileStream(savePath, FileMode.Create, FileAccess.Write))
            {
                fileStream.SetLength(fileSize);

                var tasks = new List<Task>();

                for (int i = 0; i < threadCount; i++)
                {
                    long startPosition = i * chunkSize;
                    long endPosition = (i == threadCount - 1) ? fileSize - 1 : (i + 1) * chunkSize - 1;
                    int threadIndex = i;

                    tasks.Add(Task.Run(async () =>
                    {
                        using (var client = new TcpClient())
                        {
                            await client.ConnectAsync(sourceIp, 8889);
                            using (var stream = client.GetStream())
                            {
                                // 发送文件路径
                                byte[] pathBytes = System.Text.Encoding.UTF8.GetBytes(filePath);
                                byte[] lengthBytes = BitConverter.GetBytes(pathBytes.Length);
                                await stream.WriteAsync(lengthBytes, 0, lengthBytes.Length);
                                await stream.WriteAsync(pathBytes, 0, pathBytes.Length);

                                // 发送块信息
                                byte[] chunkInfo = new byte[16];
                                BitConverter.GetBytes(startPosition).CopyTo(chunkInfo, 0);
                                BitConverter.GetBytes(endPosition).CopyTo(chunkInfo, 8);
                                await stream.WriteAsync(chunkInfo, 0, chunkInfo.Length);

                                // 下载数据
                                byte[] buffer = new byte[BufferSize];
                                long position = startPosition;
                                long totalDownloaded = 0;

                                while (position <= endPosition)
                                {
                                    int bytesToRead = (int)Math.Min(BufferSize, endPosition - position + 1);
                                    int bytesRead = await stream.ReadAsync(buffer.AsMemory(0, bytesToRead));

                                    if (bytesRead == 0) break;

                                    lock (lockObject)
                                    {
                                        fileStream.Position = position;
                                        fileStream.Write(buffer, 0, bytesRead);
                                    }

                                    position += bytesRead;
                                    totalDownloaded += bytesRead;

                                    // 更新进度
                                    bytesDownloaded[threadIndex] = totalDownloaded;
                                    long totalBytesDownloaded = bytesDownloaded.Sum();
                                    
                                    var downloadProgress = new DownloadProgress
                                    {
                                        BytesTransferred = totalBytesDownloaded,
                                        TotalBytes = fileSize,
                                        Speed = totalBytesDownloaded / (DateTime.Now - startTime).TotalSeconds
                                    };

                                    progress?.Report(downloadProgress);
                                }
                            }
                        }
                    }));
                }

                await Task.WhenAll(tasks);

                // 确保进度显示为100%
                progress?.Report(new DownloadProgress
                {
                    BytesTransferred = fileSize,
                    TotalBytes = fileSize,
                    Speed = fileSize / (DateTime.Now - startTime).TotalSeconds
                });
            }
        }
    }
}